/**
 * @author Samuel Gonzalez
 * @version 1.0.6 Thu May 10, 2012 10:04PM GMT-400
 */

/*
 * Copyright (C) 2011  Samuel Gonzalez, PR
 * BenchGraph. Generates graphics and HTML tables based on HTTPERF output.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * 
 * In addition, as a special exception, the copyright holders give permission
 * to link the code of this work with the OpenSSL project's "OpenSSL" library
 * (or with modified versions of it that use the same license as the "OpenSSL" 
 * library), and distribute linked combinations including the two.  You must
 * obey the GNU General Public License in all respects for all of the code
 * used other than "OpenSSL".  If you modify this file, you may extend this
 * exception to your version of the file, but you are not obligated to do so.
 * If you do not wish to do so, delete this exception statement from your
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 
 */

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


public class Httperf {
	// Attributes
	private ArrayList<ArrayList<String>> data; // Ragged array
		
	/**
	 * Initialize attributes to default values
	 */
	public Httperf(){
		this.data = new ArrayList<ArrayList<String>>();
	}
	
	/**
	 * Assign attributes the received values
	 * @param dir - file's directory
	 * @param fn - file's name
	 * @param ff - file's format (type)
	 */
	public Httperf(String dir, String fn, String ff){
		setData(new ArrayList<ArrayList<String>>());
		loadFile(dir, fn, ff);
	}
	
	/**
	 * Return data
	 * @return
	 */
	public ArrayList<ArrayList<String>> getData(){ // Getter
		return this.data;
	}
	
	/**
	 * Set data
	 * @param data
	 */
	public void setData(ArrayList<ArrayList<String>> data){
		this.data = (data != null)? data : null;
	}
	
	/**
	 * Call specific method depending on file format (type)
	 * @param directory
	 * @param filename
	 * @param fileformat
	 */
	public void loadFile(String directory, String filename, String fileformat){
		if(fileformat.equalsIgnoreCase("txt"))
			loadTxt(directory + filename + "." + fileformat);
		else if(fileformat.equalsIgnoreCase("csv"))
			loadCsv(directory + filename + "." + fileformat);
		else if(fileformat.equalsIgnoreCase("xml"))
			loadXml(directory + filename + "." + fileformat);
		else {
			Console.wln("File format not supported.");
			System.exit(1);
		}
	}
	
	/**
	 * Load txt file from httperf
	 * @param filename
	 */
	private void loadTxt(String filename){
		
		try{
			
			// Counts file total lines
			Scanner inFile = new Scanner(new File(filename));
			
			// Opens file for reading data
			inFile = new Scanner(new File(filename));
			
			// Read file content while not eof.
			// Split data by ": "
			// data arrays is allocated the same size of array results for each iteration
			// Copy data from results into data array.
			
			this.data = new ArrayList<ArrayList<String>>();
			while(inFile.hasNext()){
				String results[] = inFile.nextLine().split(": ");
				this.data.add(new ArrayList<String>());
				for(int j = 0; j < results.length; j++)
					this.data.get(this.data.size() - 1).add(results[j]);
			}
			
			inFile.close();
			
		}catch(FileNotFoundException e){
			Console.wln("File specified was not found.");
			System.exit(1);
		}
	}
	
	/**
	 * Load csv file from httperf
	 * @param filename
	 */
	private void loadCsv(String filename){
		
		try {
			// Open file for reading
			Scanner inFile = new Scanner(new File(filename));
			
			// Declare variables and results array
			String[] variables = null, results = null;
						
			// Read file, splits data, and get file lines.
			while(inFile.hasNext()){
				variables = inFile.nextLine().split(",");
				results = inFile.nextLine().split(",");
			}
			
			inFile.close();
			
			// Organize data in proper way to be analyzed
			this.data = new ArrayList<ArrayList<String>>();
			
			// Data mining
			String[] split;
			for(int i = 0; i < results.length; i++){
				 split = results[i].split(":");
				 this.data.add(new ArrayList<String>(split.length + 1));
				 //this.data[i] = new String[split.length + 1];
				 this.data.get(this.data.size() - 1).add(variables[i]);
				 //this.data[i][0] = variables[i];
				 for(int j = 0; j < split.length; j++){
					 this.data.get(this.data.size() - 1).add(split[j]);
				 }
			}
			
			variables = null; results = null; // Garbage Collector purpose
			
		}catch(FileNotFoundException e){
			Console.wln("File specified was not found.");
			System.exit(1);
		}	
	}
	
	/**
	 * Load xml file from httperf
	 * @param filename
	 */
	private void loadXml(String filename){
		try {

			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser saxParser = factory.newSAXParser();

			DefaultHandler handler = new DefaultHandler() {

				public void startElement(String uri, String localName,String qName, Attributes attributes) {

					if(qName.equalsIgnoreCase("TOTAL_") || 
							qName.equalsIgnoreCase("CONNECTION_RATE") ||
							qName.equalsIgnoreCase("CONNECTION_TIME") ||
							qName.equalsIgnoreCase("REQUEST_RATE") ||
							qName.equalsIgnoreCase("REQUEST_SIZE") ||
							qName.equalsIgnoreCase("REPLY_RATE") ||
							qName.equalsIgnoreCase("REPLY_SIZE") ||
							qName.equalsIgnoreCase("REPLY_TIME") ||
							qName.equalsIgnoreCase("REQUEST_SIZE") ||
							qName.equalsIgnoreCase("REQUEST_SIZE") ||
							qName.equalsIgnoreCase("REPLY_STATUS") ||
							qName.equalsIgnoreCase("REQUEST_SIZE") ||
							qName.equalsIgnoreCase("CPU_TIME") ||
							qName.equalsIgnoreCase("NET_IO") ||
							qName.equalsIgnoreCase("ERRORS")) {
						data.add(new ArrayList<String>());
						data.get(data.size() - 1).add(qName.trim());
					} else if(!qName.equalsIgnoreCase("SERVER_RESULTS")){
						data.get(data.size() - 1).add(qName.trim());
					}
				}

				public void characters(char ch[], int start, int length) throws SAXException {
					if(data.size() > 0){
						if(data.get(data.size() - 1) != null){
							data.get(data.size() - 1).add(new String(ch, start, length).trim());
						}
					}
				}

			};

			saxParser.parse(filename, handler);
			
			// Clean up
			for(int i = 0; i < data.size(); i++){
				ArrayList<String> arr = new ArrayList<String>();
				for(int j = 0; j < data.get(i).size(); j++){
					if(data.get(i) != null && data.get(i).get(j) != null){
						if(!data.get(i).get(j).isEmpty()){
							if(data.get(i).get(j).equalsIgnoreCase(">") || data.get(i).get(j).equalsIgnoreCase("<")){
								String tmp = data.get(i).get(j) + " " + data.get(i).get(j + 1);
								arr.add(tmp);
								data.get(i).remove(j + 1);
							} else {
								arr.add(data.get(i).get(j));
							}
						}
					}
				}
				data.set(i, arr);
			}
			
			// Replaces "_" for a white space
			for(ArrayList<String> list : data){
				for(int i = 0; i < list.size(); i++){
					list.set(i, list.get(i).replace("_", " "));
				}
			}
			
			// Debug Purposes
			// Display
			/*for(int i = 0; i < data.size(); i++){
				for(int j = 0; j < data.get(i).size(); j++){
							System.out.println(data.get(i).get(j));
				}
			}*/

		} catch (IllegalArgumentException iae) {
			Console.wln("Illegal path provided.");
			System.exit(1);
		} catch (SAXException saxe) {
			Console.wln(saxe.getMessage().toString());
			System.exit(1);
		} catch (IOException ioe) {
			Console.wln(ioe.getMessage().toString());
			System.exit(1);
		} catch (ParserConfigurationException pce) {
			Console.wln("Configuration Error.");
			System.exit(1);
		}
	}
}

